Adding your own code to the generated classes
Although LLBLGen Pro still supports user regions in generated code, we don't recommend adding code to these regions anymore and therefore we have removed all documentation regarding user code regions. If you have to maintain code with user code regions with custom code, please migrate the code in user code regions to partial classes.
The generated code contains Xmldoc comments with a lot of information. It's recommended to generate documentation from these Xmldoc comments using tools like Sandcastle Help File Builder to learn more where extension points are available, e.g. where partial methods are implemented.
Sometimes you want to add your own functionality to the generated code, use it as a base to build upon. Adding your own code to generated classes has the downside that when you re-generate the code into the same folder, your changes will be overwritten.
LLBLGen Pro offers several ways to add your own code to the generated code to avoid that from happening:
- Through partial classes (Recommended).
- Through include templates, which are templates which are merged at generation time with the standard templates to allow you to merge your own template code with the standard templates without altering the standard templates.
This section describes in detail the user code regions and the include templates in greater detail. For include templates it's recommended read the LLBLGen Pro SDK documentation.
Using partial classes is straight forward and therefore it's discussed only briefly in this section.
We recommend using partial classes to add user code or, if code that is added can be added through automation, use include templates or add your own templates and code generation tasks to the set of tasks executed at code generation time.
Partial classes
LLBLGen Pro generates all classes generated for the LLBLGen Pro runtime framework as partial classes. For VB.NET this doesn't make a difference as any class can be extended by another code file with a partial class definition with the same name, though in C#, all classes are generated as partial classes.
To extend any class in the generated code, just define in the same namespace and assembly a new definition of an existing class and specify the keyword partial (C#) or Partial (VB.NET).
For example, consider an entity CustomerEntity being generated by LLBLGen Pro. You can then extend this class by adding a new file to the generated Visual Studio project and add the following code to that file: (the rootnamespace used for this project was 'Northwind')
namespace Northwind.EntityClasses
{
public partial class CustomerEntity
{
// your code here
}
}
You can then add your code to this class which will then be compiled into the class with the same name in the same project by Visual Studio. Be aware that you're not inheriting a class, so you can't specify a method or property with a name already in the generated code's class
The generated code contains several base classes from which other classes inherit, e.g. the CommonEntityBase class. These classes are a great place to add code (through partial classes) to a large group of classes.
Include templates
Include templates is an advanced topic for which it's recommended you've read the the LLBLGen Pro SDK (available to customers) documentation. It is possible to get started without the SDK, but it is recommended to consult the SDK for further details.
LLBLGen Pro's code generator engines can handle include templates, which means that in a template, a template include statement can be added and the contents of the template bound to the template id specified in the template include statement will replace the template include statement. This is similar to the well known include tags for ASP pages.
The includes can be used recursively, which means an included template can again contain include statements. At various places in the templates of the SelfServicing and Adapter template groups, include statements are added. Furthermore, several templates have been broken into several templates to make it easier to adjust the generated code through include templates.
As include templates work with template id's, using a template bindings file which binds a different code file to a template id can make the generated code look different: your template will be included into the standard template and executed together with the standard template.
Please also see Concepts - Templates and Template groups and the LLBLGen Pro Designer documentation for more information about templatebindings files and how to use them in the designer, for example how to make your template overrule a standard template.
To easily create templatebindings files, please use the templateBindingsDefinition.xsd file in the TasksXSDs folder in the LLBLGen Pro installation folder. If you first open the .xsd in Visual Studio and then your templatebindings file, you have intellisense on the xml you write in your templatebindings file.
Below is a list of template id's you can add to your own templatebindings file and which will make the contents of the file bound to the template id be inserted into the template the template is included in. There are more template ids defined for this purpose, though beginners should start with this list. The full list is available in the SDK documentation.
TemplateID | Description | Included in |
---|---|---|
Custom_CommonEntityBaseTemplate | Custom include template ID for the template which is used for the CommonEntityBase class, which is the class sitting in between the EntityBase(2) classes and the generated entity classes. | The CommonEntityBase class. |
Custom_ConstantsEnumsTemplate | Custom include template ID for the template which is used for the ConstantsEnums codefile. | The Root namespace specification of SD_ConstantsEnumsTemplate |
Custom_DataAccessAdapterTemplate | Custom include template ID for the general data access adapter object. Database specific. Adapter specific. | The DataAccessAdapter class |
Custom_CommonDAOBaseTemplate | Custom include template ID for the template which is used for the CommonDaoBase helper class. | The CommonDaoBase class |
Custom_EntityAdapterTemplate | Custom include template ID for entity classes. Adapter specific. | The EntityNameEntity classes. |
Custom_EntityBaseTemplate | Custom include template ID for the template which is used for the entity base classes in a scenario where two classes per entity are generated. | The EntityNameEntityBase classes |
Custom_EntityCollectionAdapterTemplate | Custom include template ID for the general collection class for all entities. Adapter specific | The EntityCollection class |
Custom_EntityCollectionTemplate | Custom include template ID for the template which is used for the Entity Collection classes. | The EntityNameCollection classes |
Custom_EntityDAOTemplate | Custom include template ID for the template which is used for the Dao classes in selfservicing. | The EntityNameDAO classes |
Custom_EntityInitializationTemplate | Custom include template ID which is used for templates which are inserted into the InitClass* methods of an entity, at the end of the init class method. | All entity classes (selfservicing/adapter) |
Custom_EntityTemplate | Custom include template ID for the template which is used for the Entity classes. | The EntityNameEntity classes. |
Custom_EntityUsingEntityBaseTemplate | Custom include template ID for the template which is used for the entity classes in a scenario where two classes per entity are generated. | The EntityNameEntity classes. |
Custom_EntityValidatorTemplate | Custom include template ID for the template which is used for the Validator classes per entity, used for per field validation. This template is included in the class, not in the method. For injection of custom validation code into the Validate method, bind SD_EntityValidatorIncludeTemplate to your custom template. | The EntityNameValidator classes. |
Custom_ResultsetFieldsAdapterTemplate | Custom include template ID for the resultsets class, used in typed lists. Adapter specific. | The ResultsetFields class |
Custom_ResultsetFieldsTemplate | Custom include template ID for the template which is used for the ResultsetFields helper class. | The ResultsetFields class |
Custom_TypedListAdapterTemplate | Custom include template ID for the typed list classes. Adapter specific. | The TypedListNameTypedList class. No include is specified for the TypedListNameTypedListRow class. |
Custom_TypedListDAOTemplate | Custom include template ID for the template which is used for the TypedList DAO class, which is also used by TypedViews. | The TypedListDAO class |
Custom_TypedListTemplate | Custom include template ID for the template which is used for the TypedList classes. | The TypedListNameTypedList class. No include is specified for the TypedListNameTypedListRow class. |
Custom_TypedViewAdapterTemplate | Custom include template ID for the TypedView classes. Adapter specific. | The TypedViewNameTypedView class. No include is specified for the TypedViewNameTypedViewRow class. |
Custom_TypedViewTemplate | Custom include template ID for the template which is used for the TypedView classes. | The TypedViewNameTypedView class. No include is specified for the TypedViewNameTypedViewRow class. |
A good place to start is adding a template binding to Custom_EntityInitializationTemplate. The contents of the template bound to that template id will then be inserted into the InitClass methods of the entity classes.
This template can for example be used to set the
ConcurrencyPredicateFactoryToUse property of every entity to an instance
of a generic IConcurrencyPredicateFactory
implementation. As it will be
code which will be generated into the generated code, you don't have to
worry about losing your additions: they're always there.
Keep your include templates with your .lgp project file so you'll always have them available with the .lgp project file. You can specify in the .lgp file an additional Templates folder where you can store the templatebindings files and templates you've created.
Include templates can be either written using Template Definition Language (TDL, which is LLBLGenPro's native template language) or using C# or VB.NET in .lpt templates (which use the <% %> syntaxis for code blocks, similar to asp syntaxis).
The tutorial below is a small tutorial to write an include template using a simple text editor or Visual Studio, as is used below.
Adding code to an entity
We will first create a new templatebindings file for our template. The template file and the templatebindings file are stored in the default folder for templates: My Documents\LLBLGen Pro\vX.Y\Templates, where X.Y is the version of the designer. e.g. 5.1
- In the LLBLGen Pro designer, open the Template Bindings Viewer and create a new template bindings file. Please consult the Designer documentation, 'How to ... work with templates... to add a new template' for details.
-
If you open the new Templatebindings file as xml inside the
designer, you should change it to look like this:
<?xml version="1.0"?> <templateBindings xmlns="http://sd/llblgen/pro/templateBindingsDefinition.xsd" name="My template bindings" description ="My include template bindings" precedenceLevel="11"> <supportedFrameworks> <framework name="LLBLGen Pro Runtime Framework"/> </supportedFrameworks> <supportedPlatforms> <platform name=".NET 4.0"/> <platform name=".NET 4.5"/> <platform name=".NET 4.5.1"/> <platform name=".NET 4.5.2"/> <platform name=".NET 4.6"/> <platform name=".NET 4.6.1"/> </supportedPlatforms> <language name="C#"> <templateBinding templateID="Custom_EntityUsingEntityBaseTemplate" filename="customEntityCodeInclude.template" /> </language> <language name="VB.NET"> <!-- If you're using VB.NET, you should add the binding above here instead. --> </language> </templateBindings>
- Verify that everything is as you want it to be, and then save MyBindings.templatebindings. Save it in a folder reachable by the designer for templates, which are automatically listed in the combo box in the save dialog.
- Click the 'Refresh the code generation meta-data' button in the toolbar or select the option from the Tools menu. The template bindings file should now be available in the templatebindings selector in the Template Bindings Viewer in the designer.
After creating the templatebindings file, we're now set to write the actual template so we can use it in the code generation process. The example above bound the template id Custom_EntityUsingEntityBaseTemplate to the template we will write in next steps. This means it will be used in SelfServicing TwoClasses scenario's. If you're using Adapter, you should specify Custom_EntityAdapterTemplate instead in the templatebindings above.
Writing the actual template takes a few steps. You can use any text editor you want.
- Select the just created templatebindings file in the Template Bindings Viewer.
- Double-click the red colored file customEntityCodeInclude.template. This should open the file in the template editor in the designer
-
Add the following code to the blank editor:
As you can see, this template contains TDL (Template Definition Language), though we also could have used a .lpt template. See for more information about .lpt templates the LLBLGen Pro SDK./// <summary> /// Example of dyn. included code. /// </summary> public string IncludedPropertyOf<[CurrentEntityName]> { get { return "I'm dynamically included in <[CurrentEntityName]>!";} }
- Save the template file.
- Load an LLBLGen Pro project file in the LLBLGen Pro designer and press F7.
- Select the .NET version of your choice and if you've specified Custom_EntityUsingEntityBaseTemplate in the templatebindings file, you should select SelfServicing as template group and on tab 3, you should select the preset for TwoClasses. If you've specified Custom_EntityAdapterTemplate in the templatebindings file, you should select Adapter as template group. It doesn't matter which preset you select. You should see your templatebindings file on tab 2 of the generator configuration dialog. (press 'Advanced' to view the 2nd and 3rd tab)
- Specify a destination folder, root namespace and press the Start Generator button.
- If you're using SelfServicing, you should open one or more derived entity classes in an editor. If you're using Adapter, you should open on or more of the generated entity classes. Examine the class' code, in the Included code region at the bottom, the property IncludedPropertyOfentityname should be present.
Using .lpt templates as include templates
As discussed briefly in the previous section, LLBLGen Pro supports two
kinds of templates: TDL templates and .lpt templates. The .lpt templates
are templates which have the template code in <% %>
brackets,
similar to various code generators out there, and the template code is
able to access every element in the LLBLGen Pro project object graph.
You can bind a .lpt template to a template ID which is used for including another template, so you can use .lpt templates as include templates. TDL templates are interpreted, .lpt templates are compiled into an assembly, though this is handled by the TDL interpreter for you and it integrates transparently.
As discussed in the LLBLGen Pro SDK, each .lpt template results in a
class which implement ITemplateClass
. In your template you have acces to
three main parameters:
- **_executingGenerator**, which is of type IGenerator, your gateway to the Project object and more. IGenerator is defined in the SD.LLBLGen.Pro.ApplicationCore assembly of the LLBLGen Pro designer.
- **_parameters**, which is a hashtable with all the parameters defined for the task currently executing, stored with the parameter name as the key.
- **_activeObject**, of type object
In your .lpt template you can access these objects and the data they contain in your script blocks. We'll see how this works by rewriting the previous example in an .lpt include template below. When a .lpt template is used as an include template, the TDL interpreter will pass on its complete state to the .lpt template in the _activeObject, which will represent a Hashtable.
The following list shows which object is stored under which key in the _activeObject's Hashtable. It contains the current scope of the TDL interpreter at the point when the template include statement was found:
- CurrentEntity, the currently set currentEntity
- CurrentRelatedEntity, the currently set related entity
- CurrentFieldOnRelatedField, the currently set currentfieldOnRelatedField
- CurrentEntityField, the currently set currentEntityField
- CurrentRelatedEntityField, the currently set currentRelatedEntityField
- CurrentEntityFieldRelation, the currently set currentEntityFieldRelation
- CurrentEntityRelation, the currently set currentEntityRelation
- CurrentTypedListRelation, the currently set currentTypedListRelation
- CurrentTypedList, the currently set currenttypedList
- CurrentTypedView, the currently set currenttypedview
- CurrentTypedListField, the currently set currentTypedlistfield
- CurrentSPCall, the currently set currentSPCall
- CurrentSPCallParameter, the currently set currentSPCallParameter
- CurrentTypedViewField, the currently set currentTypedViewField
Keys are strings, values are objects or null if not set.
With this knowledge we can rewrite previous section's tutorial a little to use a .lpt include template instead:
- Open MyBindings.template and change customEntityCodeInclude.template into customEntityCodeInclude.lpt and save the file.
- Create a new template file, customEntityCodeInclude.lpt in the folder LLBLGen Pro installation folderTemplates and open it in a text editor
-
Add the following code to the template
and save the file.<% EntityDefinition currentEntity = (EntityDefinition)((Hashtable)_activeObject)["CurrentEntity"]; %> /// <summary> /// Example of dyn. included code. /// </summary> public string IncludedPropertyOf<%=currentEntity.Name%> { get { return "I'm dynamically included in <%=currentEntity.Name%>!";} }
You should then again generate code as previously stated. It should give you the same code as before.